package com.efeichong.common.security;

import com.efeichong.common.domain.RoleMenuVo;
import com.efeichong.common.domain.entity.redis.LoginUser;
import com.efeichong.common.domain.repository.redis.LoginUserRepository;
import com.efeichong.jpa.JExample;
import com.efeichong.project.domain.dao.db.SysMenuDao;
import com.efeichong.project.domain.dao.db.SysUserDao;
import com.efeichong.project.domain.entity.db.SysRole;
import com.efeichong.project.domain.entity.db.SysUser;
import com.efeichong.uuid.UUIDUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用户验证处理
 *
 * @author qinghong
 */
@Service
@Slf4j
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    LoginUserRepository loginUserRepository;
    @Autowired
    SysMenuDao sysMenuDao;
    @Autowired
    private SysUserDao sysUserDao;
    @Value("${token.expire}")
    private String expire;
    @Value("${token.singleLogin}")
    private boolean singleLogin;

    @Override
    public UserDetails loadUserByUsername(String username) throws AuthenticationServiceException {
        Optional<SysUser> optional = sysUserDao.selectOne(JExample.of("username", username));
        if (!optional.isPresent()) {
            log.warn("登录用户：{} 不存在", username);
            throw new AuthenticationServiceException("用户或密码错误");
        }
        SysUser sysUser = optional.get();
        if (sysUser.getHasDel() == 1) {
            log.warn("登录用户：{} 不存在", username);
            throw new AuthenticationServiceException("用户或密码错误");
        } else if (sysUser.getStatus() == 0) {
            log.warn("登录用户：{} 已被停用", username);
            throw new AuthenticationServiceException("用户或密码错误");
        }
        return createLoginUser(sysUser);
    }

    public UserDetails createLoginUser(SysUser sysUser) {
        List<SysRole> sysRoles = sysUser.getSysRoles();
        Set<SimpleGrantedAuthority> roleList = sysRoles.stream().map(sysRole -> new SimpleGrantedAuthority(sysRole.getCode())).collect(Collectors.toSet());

        LoginUser loginUser;
        Optional<LoginUser> optional = loginUserRepository.findById(sysUser.getId());
        if (optional.isPresent()) {
            //singleLogin  true同账户不允许多地登陆  false 同账户可以多地登陆
            if (!singleLogin) {
                //同账户可以多地登陆,再次登录则刷新过期时间
                loginUser = optional.get();
                loginUser.setUsername(sysUser.getUsername());
                loginUser.setPassword(sysUser.getPassword());
                loginUser.setAuthorities(roleList);
                JExample example = JExample.of("sysRoles.users.id", sysUser.getId());
                example.setDistinct(true);
                List<RoleMenuVo> roleMenuVos = sysMenuDao.selectAll(example, RoleMenuVo.class);
                loginUser.setPermissions(roleMenuVos);
                loginUser.setExpire(Long.valueOf(expire));
                loginUserRepository.save(loginUser);
                return loginUser;
            }
        }
        loginUser = new LoginUser();
        loginUser.setId(sysUser.getId());
        String token = UUIDUtils.getId();
        loginUser.setToken(token);
        loginUser.setUsername(sysUser.getUsername());
        loginUser.setPassword(sysUser.getPassword());
        loginUser.setAuthorities(roleList);
        JExample example = JExample.of("sysRoles.users.id", sysUser.getId());
        example.setDistinct(true);
        List<RoleMenuVo> roleMenuVos = sysMenuDao.selectAll(example, RoleMenuVo.class);
        loginUser.setPermissions(roleMenuVos);
        loginUser.setExpire(Long.valueOf(expire));
        loginUserRepository.save(loginUser);
        return loginUser;
    }

}
